import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { onBeforeUnmount, onMounted, Ref, ref, shallowRef } from 'vue'

import MyTransform from './MyTransform.js'

export function useThree(containerRef: Ref<HTMLDivElement | undefined>) {
  const status = ref<'start' | 'end'>('start')
  const width = ref(100)
  const height = ref(100)
  const controls = shallowRef<OrbitControls | null>(null)
  const transformControls = shallowRef<MyTransform[]>([])
  const renderer = shallowRef<THREE.WebGLRenderer | null>(null)
  const scene = shallowRef<THREE.Scene | null>(null)
  const camera = shallowRef<THREE.PerspectiveCamera | null>(null)
  const threeModel = shallowRef<THREE.Group | null>(null)
  const modelCenter = ref({
    x: 0,
    y: 0,
    z: 0,
  })
  const modelSize = ref({
    x: 0,
    y: 0,
    z: 0,
  })
  const views = ref<
    {
      camera: THREE.OrthographicCamera
      left: number
      bottom: number
      width: number
      height: number
      distance: THREE.Vector3
      layers: number[]
      id: string
      showControl: {
        x: boolean
        y: boolean
        z: boolean
      }
    }[]
  >([
    {
      camera: new THREE.OrthographicCamera(),
      left: 2 / 3,
      bottom: 0,
      width: 1 / 3,
      height: 1 / 3,
      distance: new THREE.Vector3(0, 2, 0),
      layers: [0, 2, 3],
      id: 'viewportThree',
      showControl: {
        x: true,
        y: false,
        z: true,
      },
    },
    {
      camera: new THREE.OrthographicCamera(),
      left: 2 / 3,
      bottom: 1 / 3,
      width: 1 / 3,
      height: 1 / 3,
      distance: new THREE.Vector3(-2, 0, 0),
      layers: [0, 2, 4],
      id: 'viewportTwo',
      showControl: {
        x: false,
        y: true,
        z: true,
      },
    },
    {
      camera: new THREE.OrthographicCamera(),
      left: 2 / 3,
      bottom: 2 / 3,
      width: 1 / 3,
      height: 1 / 3,
      distance: new THREE.Vector3(0, 0, 2),
      layers: [0, 2, 5],
      id: 'viewportOne',
      showControl: {
        x: true,
        y: true,
        z: false,
      },
    },
  ])

  function animate() {
    // renderer.value?.setClearColor(0xf0f0f0, 1)
    renderer.value?.setScissorTest(true)
    renderer.value?.setScissor(0, 0, width.value * (2 / 3), height.value)
    renderer.value?.setViewport(0, 0, width.value * (2 / 3), height.value)
    renderer.value?.render(scene.value!, camera.value!)
    views.value?.forEach((item) => {
      renderer.value?.setScissor(
        item.left * width.value,
        item.bottom * height.value,
        item.width * width.value,
        item.height * height.value,
      )
      renderer.value?.setViewport(
        item.left * width.value,
        item.bottom * height.value,
        item.width * width.value,
        item.height * height.value,
      )
      const distance = Math.max(
        modelSize.value.x,
        modelSize.value.y,
        modelSize.value.z,
      )
      item.camera.position.copy({
        x: modelCenter.value.x + item.distance.x * distance,
        y: modelCenter.value.y + item.distance.y * distance,
        z: modelCenter.value.z + item.distance.z * distance,
      })
      item.camera.lookAt(
        modelCenter.value.x,
        modelCenter.value.y,
        modelCenter.value.z,
      )
      renderer.value?.render(scene.value!, item.camera)
    })
    renderer.value?.setScissorTest(false)
    controls.value?.update()
  }
  const init = () => {
    width.value = containerRef.value?.clientWidth || 100
    height.value = containerRef.value?.clientHeight || 100
    camera.value = new THREE.PerspectiveCamera(
      45,
      (width.value * (2 / 3)) / height.value,
      0.1,
      10000,
    )
    camera.value.viewport = new THREE.Vector4(
      0,
      0,
      width.value * (2 / 3),
      height.value,
    )

    // 主相机图层设置
    camera.value.layers.enable(0)
    camera.value.layers.enable(1)
    camera.value.layers.enable(2)
    // camera.value.layers.enable(3)
    // camera.value.layers.enable(4)
    // camera.value.layers.enable(5)

    scene.value = new THREE.Scene()
    // scene.value.background = new THREE.Color(0xf0f0f0)

    const ambientLight = new THREE.AmbientLight(0xffffff, 1)
    scene.value.add(ambientLight)

    const pointLight = new THREE.PointLight(0xffffff, 1)
    camera.value.add(pointLight)

    renderer.value = new THREE.WebGLRenderer({ antialias: true, alpha: true })
    renderer.value.shadowMap.enabled = true
    renderer.value.setPixelRatio(window.devicePixelRatio)
    renderer.value.setSize(width.value, height.value)
    renderer.value.setAnimationLoop(animate)
    containerRef.value?.appendChild(renderer.value.domElement)

    controls.value = new OrbitControls(
      camera.value,
      document.getElementById('mainViewport'),
    )
    controls.value.enableDamping = false
    controls.value.minDistance = 0.2

    // views.value.forEach((view) => {
    //   const control = new MyTransform(
    //     view.camera,
    //     document.getElementById(view.id)!,
    //     [view.layers[view.layers.length - 1]],
    //   )
    //   control.setShowHandler({
    //     showX: view.showControl.x,
    //     showY: view.showControl.y,
    //     showZ: view.showControl.z,
    //   })
    //   scene.value?.add(control.root)
    //   transformControls.value.push(control)
    //   //   const control2 = new OrbitControls(
    //   //     view.camera,
    //   //     document.getElementById(view.id)!,
    //   //   )
    //   //   control2.enablePan = false
    //   //   transformControls.value.push(control)
    // })

    // views.value.forEach((view, index) => {
    //   const control = new TransformControls(
    //     view.camera,
    //     document.getElementById(view.id)!,
    //   )
    //   // control.setMode('translate')
    //   control.setMode('scale')
    //   control.showX = view.showControl.x
    //   control.showY = view.showControl.y
    //   control.showZ = view.showControl.z

    //   const control2 = new OrbitControls(
    //     view.camera,
    //     document.getElementById(view.id)!,
    //   )
    //   control2.enablePan = false
    //   transformControls.value.push(control)
    //   const gizmo = control.getHelper()
    // gizmo.layers.set(view.layers[view.layers.length - 1])
    // gizmo.traverse((child) => {
    //   child.layers.set(view.layers[view.layers.length - 1])
    // })

    //   const raycaster = control.getRaycaster()

    //   raycaster.layers.enableAll()
    //   scene.value?.add(gizmo)
    //   console.log(control)
    // })
  }

  const addModel = (model: THREE.Group) => {
    threeModel.value = model
    model.castShadow = true
    // 1. 计算模型的世界包围盒
    const bbox = new THREE.Box3().setFromObject(threeModel.value)
    const size = bbox.getSize(new THREE.Vector3())

    // 2. 计算模型底部需要补偿的高度
    // const modelBottomY = bbox.min.y // 模型最低点的Y坐标
    // const offsetY = -modelBottomY // 需要向上移动的距离

    // // 3. 调整模型位置
    // threeModel.value.position.y += offsetY

    const newBbox = new THREE.Box3().setFromObject(threeModel.value)
    const newCenter = newBbox.getCenter(new THREE.Vector3())
    console.log('newCenter', newCenter)
    modelCenter.value = {
      x: newCenter.x,
      y: newCenter.y,
      z: newCenter.z,
    }
    modelSize.value = {
      x: size.x,
      y: size.y,
      z: size.z,
    }

    const maxSize = Math.max(size.x, size.y, size.z)
    const cameraDistance = maxSize * 3 // 2倍模型尺寸的距离

    camera.value?.position.copy(newCenter)
    camera.value?.position.set(
      newCenter.x + cameraDistance * Math.sin(Math.PI / 6),
      newCenter.y + cameraDistance * Math.sin(Math.PI / 6),
      newCenter.z + cameraDistance * Math.cos(Math.PI / 6),
    )
    const aspect = (width.value * (1 / 3)) / (height.value * (1 / 3))
    views.value.forEach((view) => {
      view.camera.left = -maxSize * aspect
      view.camera.right = maxSize * aspect
      view.camera.top = maxSize
      view.camera.bottom = -maxSize
      view.camera.near = 0.1
      view.camera.far = 10000
      view.layers.forEach((layer) => {
        view.camera.layers.enable(layer)
      })
      view.camera.updateProjectionMatrix()
    })
    views.value.forEach((item) => {
      console.log(
        'cameraLayer',
        item.camera.layers.mask.toString(2).padStart(32, '0'),
      )
    })

    camera.value?.lookAt(newCenter)

    // 4. 添加到场景
    threeModel.value.layers.enable(0)
    // threeModel.value.layers.enable(3)
    // threeModel.value.layers.enable(4)
    // threeModel.value.layers.enable(5)

    scene.value?.add(threeModel.value)

    // const gridSize = maxSize * 5
    // const divisions = 10

    // const gridHelper = new THREE.GridHelper(gridSize, divisions, '', '#000000')
    // gridHelper.material = new THREE.LineBasicMaterial({ color: 0x00ff00 })

    // gridHelper.position.set(0, -modelSize.value.y / 2, 0)
    // scene.value?.add(gridHelper)
    // const planeGeometry = new THREE.PlaneGeometry(
    //   modelSize.value.x * 3,
    //   modelSize.value.z * 3,
    // ) // 宽度和高度
    // const planeMaterial = new THREE.MeshStandardMaterial({
    //   color: 0xe6e7ee, // 颜色
    //   side: THREE.FrontSide, // 双面渲染（可选）
    //   metalness: 0.1,
    //   roughness: 0.5,
    // })

    // // 2. 创建平面网格
    // const plane = new THREE.Mesh(planeGeometry, planeMaterial)

    // // 3. 旋转平面（默认是竖立的，需要平放）
    // plane.rotation.x = -Math.PI / 2 // 旋转90度使其水平

    // // 4. 调整位置（可选）
    // plane.position.y = -modelSize.value.y / 2 // 放在模型下方

    // // 5. 添加到场景
    // scene.value?.add(plane)

    // // 6. 如果需要接收阴影（如模型投射阴影到地面）
    // plane.receiveShadow = true
    const radius = Math.max(modelSize.value.x, modelSize.value.z)
    const segments = 32
    // const textureLoader = new THREE.TextureLoader()
    // textureLoader.setPath('/src/assets/')
    // const groundTexture = textureLoader.load('backgroud.jpg')
    const canvas = document.createElement('canvas')
    canvas.width = 256
    canvas.height = 256
    const ctx = canvas.getContext('2d')
    if (!ctx) return
    const gradient = ctx.createRadialGradient(128, 128, 0, 128, 128, 128)
    gradient.addColorStop(0, 'white')
    gradient.addColorStop(1, 'black')
    ctx.fillStyle = gradient
    ctx.fillRect(0, 0, 256, 256)

    // 2. 转换为Three.js纹理
    const alphaMap = new THREE.CanvasTexture(canvas)
    // 1. 创建圆形几何体
    const circleGeometry = new THREE.CircleGeometry(radius, segments)

    const circleMaterial = new THREE.MeshStandardMaterial({
      color: 0xe6e7ee,
      transparent: true,
      alphaMap,
      // map: groundTexture,
      side: THREE.FrontSide,
      // roughness: 0.5,
      // clearcoat: 1.0, // 表面涂层（增强反射模糊）
      // clearcoatRoughness: 0.5, // 涂层模糊度（0=光滑，1=模糊）
    })

    // 2. 创建圆形网格
    const circle = new THREE.Mesh(circleGeometry, circleMaterial)

    // 3. 旋转并放置
    circle.rotation.x = -Math.PI / 2 // 平放
    circle.position.y = modelCenter.value.y - modelSize.value.y / 2 // 放在模型下方
    circle.receiveShadow = true
    // 4. 添加到场景
    scene.value?.add(circle)
  }

  const addLabel = (mesh: THREE.Mesh) => {
    scene.value?.add(mesh)
    setTransform(mesh)
  }

  const setTransform = (mesh: THREE.Mesh) => {
    transformControls.value?.forEach((control) => {
      control.attach(mesh)
    })
  }

  const onResize = () => {
    width.value = containerRef.value?.clientWidth || 100
    height.value = containerRef.value?.clientHeight || 100
    // 重置渲染器输出画布canvas尺寸
    renderer.value?.setSize(width.value, height.value)
    // 全屏情况下：设置观察范围长宽比aspect为窗口宽高比
    camera.value!.aspect = (width.value * (2 / 3)) / height.value
    // 如果相机视锥体相关参数发生了变化，需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
    camera.value!.updateProjectionMatrix()
    const bbox = new THREE.Box3().setFromObject(threeModel.value!)
    const size = bbox.getSize(new THREE.Vector3())
    const maxSize = Math.max(size.x, size.y, size.z)
    const aspect = (width.value * (1 / 3)) / (height.value * (1 / 3))
    views.value.forEach((view) => {
      view.camera.left = -maxSize * aspect
      view.camera.right = maxSize * aspect
      view.camera.top = maxSize
      view.camera.bottom = -maxSize
      view.camera.near = 0.1
      view.camera.far = 10000
      view.camera.updateProjectionMatrix()
    })
  }

  onMounted(() => {
    init()
    window.addEventListener('resize', onResize)
    status.value = 'end'
  })

  onBeforeUnmount(() => {
    if (renderer.value) {
      renderer.value.dispose()
      if (renderer.value.domElement.parentNode) {
        renderer.value.domElement.parentNode.removeChild(
          renderer.value.domElement,
        )
      }
    }
  })

  return {
    threeModel,
    modelSize,
    modelCenter,
    renderer,
    scene,
    camera,
    controls,
    addModel,
    addLabel,
    setTransform,
  }
}
